package org.dousb.doupicture.interfaces.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.dousb.doupicture.application.service.SpaceApplicationService;
import org.dousb.doupicture.application.service.UserApplicationService;
import org.dousb.doupicture.domain.user.constant.UserConstant;
import org.dousb.doupicture.domain.user.entity.Space;
import org.dousb.doupicture.domain.user.entity.User;
import org.dousb.doupicture.domain.user.valueobject.SpaceLevelEnum;
import org.dousb.doupicture.infrastructure.annotation.AuthCheck;
import org.dousb.doupicture.infrastructure.common.BaseResponse;
import org.dousb.doupicture.infrastructure.common.DeleteRequest;
import org.dousb.doupicture.infrastructure.common.ErrorCode;
import org.dousb.doupicture.infrastructure.common.ResultUtils;
import org.dousb.doupicture.infrastructure.exception.BusinessException;
import org.dousb.doupicture.infrastructure.exception.ThrowUtils;
import org.dousb.doupicture.infrastructure.utils.RedisCacheUtil;
import org.dousb.doupicture.interfaces.assembler.SpaceAssembler;
import org.dousb.doupicture.interfaces.dto.space.*;
import org.dousb.doupicture.interfaces.vo.space.SpaceVO;
import org.dousb.doupicture.shared.auth.SpaceUserAuthManager;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 空间接口
 */
@RestController
@RequestMapping("/space")
@Slf4j
public class SpaceController {

    /**
     * 本地缓存
     */
    private final Cache<String, String> LOCAL_CACHE =
            Caffeine.newBuilder().initialCapacity(1024)
                    .maximumSize(10000L)
                    .expireAfterWrite(10, TimeUnit.MINUTES)
                    .build();
    @Resource
    private SpaceApplicationService spaceApplicationService;
    @Resource
    private UserApplicationService userApplicationService;
    @Resource
    private RedisCacheUtil redisCacheUtil;
    @Resource
    private SpaceUserAuthManager spaceUserAuthManager;


    /**
     * 添加空间
     *
     * @param spaceAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Long> addSpace(@RequestBody SpaceAddRequest spaceAddRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(spaceAddRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userApplicationService.getLoginUser(request);
        long spaceId = spaceApplicationService.addSpace(spaceAddRequest, loginUser);
        return ResultUtils.success(spaceId);
    }

    /**
     * 删除空间
     * 仅本人或者管理员可用
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deletePicture(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(deleteRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userApplicationService.getLoginUser(request);
        Long id = deleteRequest.getId();
        //判断空间是否存在
        Space oldSpace = spaceApplicationService.getById(id);
        ThrowUtils.throwIf(oldSpace == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
        //仅本人或者管理员可以删除
        if (!oldSpace.getUserId().equals(loginUser.getId()) && !loginUser.isAdmin()) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限删除");
        }
        //操作数据库
        boolean result = spaceApplicationService.removeById(id);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "删除失败");
        return ResultUtils.success(true);
    }

    /**
     * 更新空间
     * 仅本人和管理员可用
     *
     * @param spaceUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateSpace(@RequestBody SpaceUpdateRequest spaceUpdateRequest, HttpServletRequest request) {
        if (spaceUpdateRequest == null || spaceUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //转换实体
        Space space = SpaceAssembler.toSpaceEntity(spaceUpdateRequest);
        //自动填充数据
        spaceApplicationService.fillSpaceBySpaceLevel(space);
        //校验参数
        spaceApplicationService.validSpace(space, false);
        //判断空间是否存在
        Long id = spaceUpdateRequest.getId();
        Space oldSpace = spaceApplicationService.getById(id);
        ThrowUtils.throwIf(oldSpace == null, ErrorCode.PARAMS_ERROR);
        //操作数据库
        boolean updateResult = spaceApplicationService.updateById(space);
        ThrowUtils.throwIf(!updateResult, ErrorCode.PARAMS_ERROR);
        return ResultUtils.success(true);
    }

//    /**
//     * 根据id获取空间
//     * 仅管理员可用
//     *
//     * @param id
//     * @return
//     */
//    @GetMapping("/get")
//    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
//    public BaseResponse<Space> getPictureById(long id) {
//        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
//        Space space = spaceApplicationService.getById(id);
//        ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR);
//        return ResultUtils.success(space);
//    }

    /**
     * 获取空间等级列表
     *
     * @return
     */
    @GetMapping("/list/level")
    public BaseResponse<List<SpaceLevel>> getSpaceLevel() {
        List<SpaceLevel> spaceLevelList = Arrays.stream(SpaceLevelEnum.values())
                .map(spaceLevelEnum -> new SpaceLevel(
                        spaceLevelEnum.getValue(),
                        spaceLevelEnum.getText(),
                        spaceLevelEnum.getMaxCount(),
                        spaceLevelEnum.getMaxSize()))
                .collect(Collectors.toList());
        return ResultUtils.success(spaceLevelList);
    }

    /**
     * 根据id获取空间包装类
     *
     * @param id
     * @param request
     * @return
     */
    @GetMapping("/get/vo")
    public BaseResponse<SpaceVO> getSpaceVOById(long id, HttpServletRequest request) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        Space space = spaceApplicationService.getById(id);
        ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR);
        SpaceVO spaceVO = spaceApplicationService.getSpaceVO(space, request);
        User loginUser = userApplicationService.getLoginUser(request);
        List<String> permissionsList = spaceUserAuthManager.getPermissionsList(space, loginUser);
        spaceVO.setPermissionList(permissionsList);
        return ResultUtils.success(spaceVO);
    }

    /**
     * 分页获取空间包装列表
     * 仅管理员可用
     *
     * @param spaceQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<SpaceVO>> listSpaceVOPage(@RequestBody SpaceQueryRequest spaceQueryRequest) {
        ThrowUtils.throwIf(spaceQueryRequest == null, ErrorCode.PARAMS_ERROR);
        long current = spaceQueryRequest.getCurrent();
        long pageSize = spaceQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(pageSize > 20, ErrorCode.PARAMS_ERROR);
        Page<Space> spacePage = spaceApplicationService.page(new Page<>(current, pageSize),
                spaceApplicationService.getQueryWrapper(spaceQueryRequest));
        Page<SpaceVO> spaceVOPage = new Page<>(current, pageSize, spacePage.getTotal());
        List<SpaceVO> spaceVOList = spaceApplicationService.getSpaceVOList(spacePage.getRecords());
        spaceVOPage.setRecords(spaceVOList);
        return ResultUtils.success(spaceVOPage);
    }

    /**
     * 编辑空间
     * 仅本人或者管理员可用
     *
     * @param spaceEditRequest
     * @param request
     * @return
     */
    @PostMapping("/edit")
    public BaseResponse<Boolean> editPicture(@RequestBody SpaceEditRequest spaceEditRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(spaceEditRequest == null, ErrorCode.PARAMS_ERROR);
        //转换实体
        Space space = SpaceAssembler.toSpaceEntity(spaceEditRequest);
        //设置编辑时间
        space.setEditTime(new Date());
        //判断空间是否存在
        Long id = spaceEditRequest.getId();
        Space oldPicture = spaceApplicationService.getById(id);
        ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
        //判断是否本人或者管理员
        User loginUser = userApplicationService.getLoginUser(request);
        if (!oldPicture.getUserId().equals(loginUser.getId()) && !loginUser.isAdmin()) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限编辑");
        }
        //操作数据库
        boolean updateResult = spaceApplicationService.updateById(space);
        ThrowUtils.throwIf(!updateResult, ErrorCode.PARAMS_ERROR);
        return ResultUtils.success(true);
    }
}
